Ext.data.DWRProxy = function(config) {
	Ext.apply(this, config);
	Ext.data.DWRProxy.superclass.constructor.call(this, config);
};
Ext.extend(Ext.data.DWRProxy, Ext.data.DataProxy, {
	re : /start|limit|sort|dir/,
	usePage : true,
	useSort : false,
	useLastParams : false,
	sort : '',
	dir : "",
	start : 0,
	limit : 10,
	paramOrder : undefined,
	dwrFnArgs : "args",
	computeParamsLen : function(dwrFn) {
		this.dwrlen = dwrFn.toString()/* 取得函数参数长度 */
				.match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").length
				- 1;
		// 默认的分页参数位置从参数末尾开始，其中倒数第1位置为limit，倒数第2位置为start，倒数第3位置为sort，
		if (!this.limitPos)
			this.limitPos = this.dwrlen - 1;
		if (!this.startPos)
			this.startPos = this.dwrlen - 2;
		if (!this.sortPos)
			this.sortPos = this.dwrlen - 3;
	},
	populatePageParmas : function(params) {
		for (var p in params) {
			if (this.re.exec(p)) {
				this[p] = params[p];
				delete params[p];
			}
		}
	},
	computeReadFnParmas : function(params) {
		alert("xx");
		var ps = Ext.apply( {}, params || {});
		this.populatePageParmas(ps);
		var len = this.dwrlen, dwrFnArgs = [];
		var loadArgs = ps[this.dwrFnArgs] || ps;
		if (loadArgs instanceof Array) { /* 通过数组传入参数 */
			for (var i = 0; i < loadArgs.length; i++)
				dwrFnArgs[i] = loadArgs[i];
		} else if (this.paramOrder) {
			for (var i = 0, len1 = this.paramOrder.length; i < len1; i++) {
				if (this.re.exec(this.paramOrder[i]))
					this[this.paramOrder[i] + "Pos"] = i;
				dwrFnArgs.push(loadArgs[this.paramOrder[i]]);
			}
		}
		/* 没有传入参数（不包含分页等）,看看有没有初始化参数 */
		if (!dwrFnArgs.length && this.initParams) {
			dwrFnArgs = this.initParams;
		}
		//查询时进行分页，能采用上一次的查询参数，但是分页参数却可以变化
		else if (!dwrFnArgs.length && this.useLastParams) {
			dwrFnArgs = this.lastParams;
		}
		// 对不足位的补undefined,如果java中是基本类型，int,float就会出现错误
		var l2 = dwrFnArgs.length;
		for (var i = l2 - 1; i < len; i++) {
			dwrFnArgs.push(undefined);
		}
		// 默认是采用分页
		if (this.usePage) {
			dwrFnArgs[this.startPos] = this.start;
			dwrFnArgs[this.limitPos] = this.limit;
			// 这里是为了防止分页时出现NAN值
			params.start = this.start;
			params.limit = this.limit;
		}
		if (this.useSort) {
			var s = this.sort + " " + this.dir
			dwrFnArgs[!this.usePage ? len - 1 : this.sortPos] = s;
		}
		this.lastParams = dwrFnArgs;
		return dwrFnArgs;
	},
	request : function(action, rs, params, reader, callback, scope, options) {
		if (!this.api[action] && !this.load) {
			throw new Ext.data.DataProxy.Error('action-undefined', action);
		}
		params = params || {};
		if ((action === Ext.data.Api.actions.read) ? this.fireEvent(
				"beforeload", this, params) : this.fireEvent("beforewrite",
				this, action, rs, params) !== false) {
			this.doRequest.apply(this, arguments);
		} else {
			callback.call(scope || this, null, options, false);
		}
	},

	doRequest : function(action, rs, params, reader, callback, scope, options) {
		var args = [];
		var dwrFn = this.api[action] || this.dwrFn;
		this.computeParamsLen(dwrFn);
		if (action == Ext.data.Api.actions.read) {
			args = this.computeReadFnParmas(params);
		} else {
			args.push(params[reader.meta.root]);
		}
		var trans = {
			params : params || {},
			callback : callback,
			scope : scope,
			arg : options,
			reader : reader
		};
		args[this.dwrlen] = this.createCallback(action, rs, trans, this);
		dwrFn.apply(Object, args);
	},
	createCallback : function(action, rs, trans, t) {
		var eh = function(message, exception) {
			t.fireEvent("loadexception", t, message, trans.callback, exception);
			trans.callback.call(trans.scope, null, trans.arg, false);
		};
		var cb = function(response) {
			if (action === Ext.data.Api.actions.read) {
				t.onRead(action, trans, response);
			} else {
				t.onWrite(action, trans, response, rs);
			}
		}
		return {
			callback : cb,
			exceptionHandler : eh
		}
	},
	onRead : function(action, trans, response) {
		var records;
		try {
			if (response && typeof response.metaData == 'string') {
				response.metaData = eval("(" + response.metaData + ")");;
			}
			records = trans.reader.readRecords(response);
		} catch (ex) {
			this.fireEvent('exception', this, 'response', action, trans, ex);
			trans.callback.call(trans.scope, null, trans.arg, false);
			return;
		}
		this.fireEvent("load", this, trans.arg);
		trans.callback.call(trans.scope, records, trans.arg, true);
	},
	onWrite : function(action, trans, response, rs) {
		this.fireEvent("write", this, action, response, rs, trans.arg);
		if (response && typeof response.metaData == 'string') {
			response.metaData = eval("(" + response.metaData + ")");;
		}
		trans.callback.call(trans.scope, response, trans.arg, true);
	}
});

Ext.data.DWRWriter = Ext.extend(Ext.data.JsonWriter, {
	writeAllFields : true,
	encode : false,
	update : function(rs) {
		var params = {};
		params[this.meta.root] = rs.data;
		return params;
	},
	destroy : function(rs) {
		// return this.update(rs);
		var params = {};
		params[this.meta.root] = rs.data;
		return params;
	},
	create : function(rs) {
		// return this.update(rs)
		var params = {};
		if (Ext.isArray(rs)) {
			var data = [];
			Ext.each(rs, function(val) {
				data.push(rs.data);
			}, this);
			params[this.meta.root] = data;
		} else if (rs instanceof Ext.data.Record) {
			params[this.meta.root] = rs.data;
		}
		return params;
	}

});
Ext.data.DWRReader = Ext.extend(Ext.data.JsonReader, {
	realize : function(rs, data) {
		if (Ext.isArray(rs)) {
			for (var i = rs.length - 1; i >= 0; i--) {
				// recurse
				if (Ext.isArray(data)) {
					this.realize(rs.splice(i, 1).shift(), data.splice(i, 1)
							.shift());
				} else {
					this.realize(rs.splice(i, 1).shift(), data);
				}
			}
		} else {
			if (Ext.isArray(data) && data.length == 1) {
				data = data.shift();
			}
			if (!this.isData(data)) {
				throw new Ext.data.DataReader.Error('realize', rs);
			}

			this.buildExtractors();
			var values = this.extractValues(data, rs.fields.items,
					rs.fields.items.length);
			rs.phantom = false; // <-- That's what it's all about
			rs._phid = rs.id; // <-- copy phantom-id -> _phid, so we can remap
			rs.id = data[this.meta.idProperty || this.meta.id];
			rs.data = values;
			rs.commit();
		}
	},
	update : function(rs, data) {
		if (Ext.isArray(rs)) {
			for (var i = rs.length - 1; i >= 0; i--) {
				if (Ext.isArray(data)) {
					this.update(rs.splice(i, 1).shift(), data.splice(i, 1)
							.shift());
				} else {
					this.update(rs.splice(i, 1).shift(), data);
				}
			}
		} else {

			if (Ext.isArray(data) && data.length == 1) {
				data = data.shift();
			}
			if (!this.isData(data)) {
				rs.commit();
				throw new Ext.data.DataReader.Error('update', rs);
			}
			this.buildExtractors();
			rs.data = this.extractValues(Ext.apply(rs.data, data),
					rs.fields.items, rs.fields.items.length);
			rs.commit();
		}
	},
	isData : function(data) {
		return (data && Ext.isObject(data) && !Ext
				.isEmpty(data[this.meta.idProperty || this.meta.id]))
				? true
				: false;
	},
	buildExtractors : function() {
		if (this.ef) {
			return;
		}
		var s = this.meta, Record = this.recordType, f = Record.prototype.fields, fi = f.items, fl = f.length;

		if (s.totalProperty) {
			this.getTotal = this.getJsonAccessor(s.totalProperty);
		}
		if (s.successProperty) {
			this.getSuccess = this.getJsonAccessor(s.successProperty);
		}
		this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p) {
			return p;
		};
		if (s.id || s.idProperty) {
			var g = this.getJsonAccessor(s.id || s.idProperty);
			this.getId = function(rec) {
				var r = g(rec);
				return (r === undefined || r === "") ? null : r;
			};
		} else {
			this.getId = function() {
				return null;
			};
		}
		var ef = [];
		for (var i = 0; i < fl; i++) {
			f = fi[i];
			var map = (f.mapping !== undefined && f.mapping !== null)
					? f.mapping
					: f.name;
			ef.push(this.getJsonAccessor(map));
		}
		this.ef = ef;
	},

	// private extractValues
	extractValues : function(data, items, len) {
		var f, values = {};
		for (var j = 0; j < len; j++) {
			f = items[j];
			var v = this.ef[j](data);
			values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue,
					data);
		}
		return values;
	},

	readResponse : function(action, response) {
		var o = (response.responseText !== undefined) ? Ext
				.decode(response.responseText) : response;
		if (!o) {
			throw new Ext.data.JsonReader.Error('response');
		}
		if (Ext.isEmpty(o[this.meta.successProperty])) {
			throw new Ext.data.JsonReader.Error('successProperty-response',
					this.meta.successProperty);
		}

		if ((action === Ext.data.Api.actions.create || action === Ext.data.Api.actions.update)) {
			if (Ext.isEmpty(o[this.meta.root])) {
				throw new Ext.data.JsonReader.Error('root-emtpy',
						this.meta.root);
			} else if (o[this.meta.root] === undefined) {
				throw new Ext.data.JsonReader.Error('root-undefined-response',
						this.meta.root);
			}
		}
		this.ef = this.buildExtractors();
		return o;
	}

});